// vim: set expandtab tabstop=4 shiftwidth=4 fdm=marker:


#include "clib_strmap.h"



/* {{{ clib_strmap::initial() */
/**
 * Initialize a string map.
 *
 * @param   appst_map   Pointor of string map link.
 * @return              0: ok, other fail.
 */
int clib_strmap::initial( clib_str_map **appst_map )
{
    if ( (*appst_map) != NULL ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if
/*
    (*appst_map) = (clib_str_map *) malloc( sizeof(clib_str_map) );
    if ( (*appst_map) == NULL ) {
        return( CLIB_STRMAP_ERR_SYST );
    } // if
    memset( *appst_map, 0, sizeof(clib_str_map) );
*/
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::destroy() */
/**
 * Destroy a string map.
 *
 * @param   appst_map   Pointor of string map link.
 * @return              always = 0.
 */
int clib_strmap::destroy( clib_str_map **appst_map )
{
    clib_str_map *p_del = NULL;
    clib_str_map *p_now = NULL;

    p_now = (*appst_map);
    while ( p_now != NULL ) {
        p_del = p_now;
        p_now = p_del->p_next;

        free( p_del );
        p_del = NULL;
    } // while

    (*appst_map) = NULL;
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::encode() */
/**
 * Replace character use in protocol.
 *
 * @param   as_str      replace string.
 * @param   ai_maxlen   string length.
 * @param   ac_keysep   key separator.
 * @param   ac_valsep   key separator.
 * @return              0: ok, other fail.
 */
int clib_strmap::encode( char      *as_str,
                         const int  ai_maxlen,
                         const char ac_keysep,
                         const char ac_valsep )
{
    int  i = 0, j = 0;
    int  i_ret = 0;
    char s_buf[CLIB_STRMAP_SLEN_LONG];
    s_buf[0] = 0;

    if ( as_str == NULL
                || ai_maxlen <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    //memset( s_buf, 0, sizeof(s_buf) );

    if ( mi_urlencode ) {
        i_ret = clib_urlencode( as_str, s_buf, sizeof(s_buf) );
        if ( i_ret != 0 ) return( CLIB_STRMAP_ERR_SYST );

    } else {
        i = 0;
        j = 0;
        while ( (i < ai_maxlen) && (as_str[i] != '\0') && (j < (int)sizeof(s_buf)-4) ) {
            switch (as_str[i]) {
            case '\t':
            case '\n':
            case '\r':
            case '%':
                snprintf( s_buf+j, CLIB_STRMAP_SLEN_LONG - j - 1, "%%%02X", as_str[i] );
                break;
            default:
                // because switch can't deal with variable.
                if ( as_str[i] == ac_keysep || as_str[i] == ac_valsep ) {
                    snprintf( s_buf+j, CLIB_STRMAP_SLEN_LONG - j - 1, "%%%02X", as_str[i] );
                } else {
                    s_buf[j] = as_str[i];
                    j -= 2;
                } // if
                break;
            } // switch
            i++;
            j += 3;
        } // while
        
        s_buf[j] = '\0';
    } // if

    snprintf( as_str, ai_maxlen, "%s", s_buf);
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::decode() */
/**
 * Decode character use in protocol.
 *
 * @param   as_str      replace string.
 * @param   ai_maxlen   string length.
 * @return              0: ok, other fail.
 */
int clib_strmap::decode( char      *as_str,
                         const int  ai_maxlen )
{
    int  i_ret = 0;
    char s_buf[CLIB_STRMAP_SLEN_LONG];

	s_buf[0] = 0;

    if ( as_str == NULL
                || ai_maxlen <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    //memset( s_buf, 0, sizeof(s_buf) );

    i_ret = clib_urldecode( as_str, s_buf, sizeof(s_buf) );
    if ( i_ret != 0 ) return( CLIB_STRMAP_ERR_SYST );

    snprintf( as_str, ai_maxlen, "%s", s_buf);
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::clib_strmap() */
/**
 * Initial clib_strmap class.
 */
clib_strmap::clib_strmap( void )
{
    mi_keycase      = CLIB_STRMAP_NO;
    mi_urlencode    = CLIB_STRMAP_YA;
    mi_throw_empty  = CLIB_STRMAP_NO;
    mc_keysep       = '&';
    mc_valsep       = '=';
    mpst_strmap     = NULL;


}
/* }}} */


/* {{{ clib_strmap::~clib_strmap() */
/**
 * Destory clib_strmap class.
 */
clib_strmap::~clib_strmap( void )
{
    this->destroy( &mpst_strmap );
}
/* }}} */


/* {{{ clib_strmap::set_case() */
/**
 * Set Key name case sensitive.
 *
 * @param   ai_case     Case sensitive or not.
 * @return              0: ok, other fail.
 */
int clib_strmap::set_case( const int ai_case )
{
    mi_keycase = (ai_case) ? (1) : (0);
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::set_urlencode() */
/**
 * Set value use URL encode/decode.
 *
 * @param   ai_use      Use URL encode/decode or not.
 * @return              0: ok, other fail.
 */
int clib_strmap::set_urlencode( const int ai_use )
{
    mi_urlencode = (ai_use) ? (1) : (0);
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::set_throw_empty() */
/**
 * Set whether throw empty value.
 *
 * @param   ai_throw    Throw empty value or not.
 * @return              0: ok, other fail.
 */
int clib_strmap::set_throw_empty( const int ai_throw )
{
    mi_throw_empty = (ai_throw) ? (CLIB_STRMAP_YA) : (CLIB_STRMAP_NO);
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::reset_key() */
/**
 * Reset key-value map.
 */
int clib_strmap::reset_key( void )
{
    return( this->destroy(&mpst_strmap) );
}
/* }}} */


/* {{{ clib_strmap::set_key() */
/**
 * Set a key-value relation.
 *
 * @param   as_key      Key name.
 * @param   as_val      Value.
 * @return              0: succ,!=0: fail.
*/
int clib_strmap::set_key( const char *as_key,
                          const char *as_val )
{
    clib_strmap_p_func  p_cmpfunc = NULL;
    clib_str_map        *p_now = NULL;
    clib_str_map        *p_end = NULL;

    if ( as_key == NULL
                || as_val == NULL
                || strlen(as_key) <= 0
                || strlen(as_val) <=  0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    if ( strlen(as_val) <= 0 && mi_throw_empty == CLIB_STRMAP_YA ) {
        return( CLIB_STRMAP_ERR_EMPT );
    } // if

    if ( mi_keycase ) {
        p_cmpfunc = strcmp;
    } else {
        p_cmpfunc = strcasecmp;
    } // if

    p_now = mpst_strmap;
    p_end = mpst_strmap;

    // find whether have some key name in link.
    while ( p_now != NULL ) {
        if ( (*p_cmpfunc)(p_now->s_key, as_key) == 0 ) {
            snprintf( p_now->s_val, sizeof(p_now->s_val), "%s", as_val );
            return( CLIB_STRMAP_OK );
        } // if
        p_end = p_now;
        p_now = p_end->p_next;
    } // while

    p_now = (clib_str_map *) malloc( sizeof(clib_str_map) );
    if ( p_now == NULL ) {
        return( CLIB_STRMAP_ERR_SYST );
    } // if
    memset( p_now, 0, sizeof(clib_str_map) );

    snprintf( p_now->s_key, sizeof(p_now->s_key), "%s", as_key );
    snprintf( p_now->s_val, sizeof(p_now->s_val), "%s", as_val );
    p_now->p_next = NULL;
    if ( p_end != NULL ) {
        p_end->p_next = p_now;
    } else {
        mpst_strmap   = p_now;
    } // if

    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::set_key() */
/**
 * Set key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
*/
int clib_strmap::set_key( const char *as_key,
                          const int   ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;

    snprintf( s_buf, sizeof(s_buf), "%d", ai_val );
    return( this->set_key(as_key, s_buf) );
}
/* }}} */

/* {{{ clib_strmap::set_key() */
/**
 * Set key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
*/
int clib_strmap::set_key( const char *as_key,
                          const unsigned int   ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;

    snprintf( s_buf, sizeof(s_buf), "%u", ai_val );
    return( this->set_key(as_key, s_buf) );
}
/* }}} */

/* {{{ clib_strmap::set_key() */
/**
 * Set key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
*/
int clib_strmap::set_key( const char *as_key,
                          const long long ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;

    snprintf( s_buf, sizeof(s_buf), "%lld", ai_val );
    return( this->set_key(as_key, s_buf) );
}
/* }}} */


/* {{{ clib_strmap::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   as_val      Value.
 * @param   ai_len      Value string length.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap::get_key( const char *as_key,
                          char       *as_val,
                          const int   ai_len )
{
    clib_strmap_p_func  p_cmpfunc = NULL;
    clib_str_map        *p_now = NULL;

    if ( as_key == NULL
                || as_val == NULL
                || strlen(as_key) <= 0
                || ai_len <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    //memset( as_val, 0, ai_len );
    if ( mi_keycase ) {
        p_cmpfunc = strcmp;
    } else {
        p_cmpfunc = strcasecmp;
    } // if

    p_now   = mpst_strmap;
    while ( p_now != NULL ) {
        if ( (*p_cmpfunc)(p_now->s_key, as_key) == 0 ) {
            snprintf( as_val, ai_len, "%s", p_now->s_val );
            return( CLIB_STRMAP_OK );
        } // if

        p_now   = p_now->p_next;
    } // while

    return( CLIB_STRMAP_ERR_FIND );
}
/* }}} */


/* {{{ clib_strmap::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap::get_key( const char *as_key,
                          int        &ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;
    int  i_ret = 0;

    i_ret = this->get_key( as_key, s_buf, sizeof(s_buf) );
    if ( CLIB_STRMAP_OK == i_ret ) {
        ai_val = atoi( s_buf );
    } // if

    return( i_ret );
}
/* }}} */

/* {{{ clib_strmap::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap::get_key( const char *as_key,
                          unsigned int        &ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;
    int  i_ret = 0;

    i_ret = this->get_key( as_key, s_buf, sizeof(s_buf) );
    if ( CLIB_STRMAP_OK == i_ret ) {
        ai_val = (unsigned int)atoll( s_buf );
    } // if

    return( i_ret );
}
/* }}} */

/* {{{ clib_strmap::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap::get_key( const char *as_key,
                          long long  &ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;
    int  i_ret = 0;

    i_ret = this->get_key( as_key, s_buf, sizeof(s_buf) );
    if ( CLIB_STRMAP_OK == i_ret ) {
        ai_val = atoll( s_buf );
    } // if

    return( i_ret );
}
/* }}} */


/* {{{ clib_strmap::get_keyname() */
/**
 * Get postion key name.
 *
 * @param   ai_pos      Postion.
 * @param   as_key      Key name.
 * @param   as_len      Key name string length.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap::get_keyname( const int   ai_pos,
                              char       *as_key,
                              const int   ai_len )
{
    int i = 0;
    clib_str_map *p_now;

    if ( ai_pos < 0
                || as_key == NULL
                || ai_len <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    p_now = mpst_strmap;
    i     = 0;
    while ( p_now != NULL && i < ai_pos ) {
        p_now = p_now->p_next;
        i++;
    } // while

    if ( p_now != NULL && i == ai_pos ) {
        snprintf( as_key, ai_len, "%s", p_now->s_key );
        return( CLIB_STRMAP_OK );
    } else {
        return( CLIB_STRMAP_ERR_FIND );
    } // if
}
/* }}} */


/* {{{ clib_strmap::count_key() */
/**
 * Get key count number.
 *
 * @return              >=0: count, <0: fail.
 */
int clib_strmap::count_key()
{
    int i_count = 0;
    clib_str_map *p_now;

    p_now   = mpst_strmap;
    i_count = 0;
    while ( p_now != NULL ) {
        i_count++;
        p_now = p_now->p_next;
    } // while

    return( i_count );
}
/* }}} */


/* {{{ clib_strmap::build() */
/**
 * Build a key-value string by a string map.
 *
 * @param   as_str      build string.
 * @param   ai_len      max length of string.
 * @param   ac_keysep   key separator, commonly='&'.
 * @param   ac_valsep   key/value separator, commonly='='.
 * @return              0: ok, other fail.
 */
int clib_strmap::build( char      *as_str,
                        const int  ai_len,
                        const char ac_keysep,
                        const char ac_valsep )
{
    char s_key[CLIB_STRMAP_SLEN_NORM];
    char s_val[CLIB_STRMAP_SLEN_LONG];
    //char s_buf[CLIB_STRMAP_SLEN_NORM + CLIB_STRMAP_SLEN_LONG + 8];
    clib_str_map *p_now;

    if ( as_str == NULL
                || ai_len <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if


    //memset( s_key,  0, sizeof(s_key) );
    //memset( s_val,  0, sizeof(s_val) );
    //memset( as_str, 0, ai_len );

    p_now = mpst_strmap;
    int i_pos = 0;
    char *s_buf = as_str;
    while ( p_now != NULL ) {
        snprintf( s_key, sizeof(s_key), "%s", p_now->s_key );
        snprintf( s_val, sizeof(s_val), "%s", p_now->s_val );
        this->encode( s_key, sizeof(s_key), ac_keysep, ac_valsep );
        this->encode( s_val, sizeof(s_val), ac_keysep, ac_valsep );

        i_pos = i_pos + strlen(s_key) + strlen(s_val) + 2;

        /// be carefull! use strcat(), as_str must have enough lenght.
        if ( i_pos <= ai_len ) {
            s_buf += snprintf( s_buf, ai_len - i_pos, "%s%c%s%c", s_key, ac_valsep, s_val, ac_keysep );
            //strcat( as_str, s_buf );
        } else {
            return( CLIB_STRMAP_ERR_LONG );
        } // if

        p_now = p_now->p_next;
    } // while

    // delete the last '&'
    i_pos--;
    as_str[i_pos] = '\0';

    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap::parse() */
/**
 * Parse a key-value string to string map.
 *
 * @param   as_str      build string.
 * @param   ai_len      string length.
 * @param   ac_keysep   key separator, commonly='&'.
 * @param   ac_valsep   key separator, commonly='='.
 * @return              0: ok, other fail.
 */
int clib_strmap::parse( const char *as_str,
                        const int   ai_len,
                        const char  ac_keysep,
                        const char  ac_valsep )
{
    char *p_split = NULL;
    //char *s_msg   = NULL;
    char s_msg[CLIB_STRMAP_SLEN_LONG]; //11k
    
    char s_delim[CLIB_STRMAP_SLEN_SHOR];
    char s_separ[CLIB_STRMAP_SLEN_SHOR];
    char s_key[CLIB_STRMAP_SLEN_NORM];
    char s_val[CLIB_STRMAP_SLEN_LONG];
    char *ps_tmp = NULL;
    int  i_ret    = 0;
    int  i_retval = 0;
    unsigned int i_pos = 0;

    if ( as_str == NULL
                || strlen(as_str) <= 0
                || ai_len <= 0 
                || strlen(as_str) >= CLIB_STRMAP_SLEN_LONG) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    //s_msg = (char *) malloc( ai_len + 8 );
    //if ( s_msg == NULL ) {
    //    return( CLIB_STRMAP_ERR_SYST );
    //} // if

    i_retval = CLIB_STRMAP_OK;
	s_msg[0] = 0;
    //memset( s_msg, 0, sizeof(s_msg) );
    //memset( s_key, 0, sizeof(s_key) );
    //memset( s_val, 0, sizeof(s_val) );

    snprintf( s_msg, ai_len+1, "%s", as_str );
    snprintf( s_delim, sizeof(s_delim), "%c\r\n", ac_keysep );
    snprintf( s_separ, sizeof(s_separ), "%c",     ac_valsep );

    p_split = strtok_r( s_msg, s_delim, &ps_tmp );
    while ( p_split != NULL ) {
        i_pos = strcspn( p_split, s_separ );

        if ( i_pos > 0 ) {
            i_pos++;
            if ( i_pos <= strlen(p_split) ) {
                snprintf( s_key, (i_pos<=sizeof(s_key))?(i_pos):(sizeof(s_key)), "%s", p_split );
                snprintf( s_val, sizeof(s_val), "%s", p_split + i_pos );
            } else { // not fine, only keyname.
                snprintf( s_key, sizeof(s_key), "%s", p_split );
                snprintf( s_val, sizeof(s_val), "%s", "" );
            } // if

            this->decode( s_key, sizeof(s_key) );
            this->decode( s_val, sizeof(s_val) );

            i_ret = this->set_key( s_key, s_val );
            if ( i_ret != CLIB_STRMAP_OK ) {
                i_retval = i_ret;
                break;
            } // if
        } // if

        p_split = strtok_r( NULL, s_delim, &ps_tmp );
    } // while

    //free( s_msg );
    return( i_retval );
}
/* }}} */




/* {{{ clib_strmap2::clib_strmap2() */
/**
 * Initial clib_strmap2 class.
 */
clib_strmap2::clib_strmap2( void )
{
    mstr_filetext = "";
    mstr_block    = "";

}
/* }}} */


/* {{{ clib_strmap2::~clib_strmap2() */
/**
 * Destory clib_strmap2 class.
 */
clib_strmap2::~clib_strmap2( void )
{
}
/* }}} */


/* {{{ clib_strmap2::reset_key() */
/**
 * Reset key-value map.
 */
int clib_strmap2::reset_key( void )
{
    mmap_key.clear();
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap2::set_key() */
/**
 * Set key value.
 *
 * @param   as_key      Key name.
 * @param   as_val      Value.
 * @return              0: succ,!=0: fail.
*/
int clib_strmap2::set_key( const char *as_key,
                          const char *as_val )
{
    map<string, string>::iterator   iter;
    char s_buf[CLIB_STRMAP_SLEN_TEXT];
    s_buf[0] = 0;
    int  i_ret = 0;

    if ( as_key == NULL
                || as_val == NULL
                || strlen(as_key) <= 0
                || strlen(as_val) <=  0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    i_ret = clib_urlencode( as_val, s_buf, sizeof(s_buf) );
    if ( 0 != i_ret ) { 
        return( CLIB_STRMAP_ERR_SYST );
    } // if

    iter = mmap_key.find( as_key );
    if ( iter != mmap_key.end() ) {
        mmap_key.erase( iter );
    } // if
    //iter = mmap_key.end();
    //mmap_key.insert( iter, map<string, string>::value_type(as_key, s_buf) );
    mmap_key.insert( map<string, string>::value_type(as_key, s_buf) );
    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap2::set_key() */
/**
 * Set key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
*/
int clib_strmap2::set_key( const char *as_key,
                          const int   ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;

    snprintf( s_buf, sizeof(s_buf), "%d", ai_val );
    return( this->set_key(as_key, s_buf) );
}
/* }}} */


/* {{{ clib_strmap2::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   as_val      Value.
 * @param   ai_len      Value string length.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap2::get_key( const char *as_key,
                          char       *as_val,
                          const int   ai_len )
{
    map<string, string>::iterator   iter;
    char s_buf[CLIB_STRMAP_SLEN_TEXT];
    s_buf[0] = 0;
    int  i_ret = 0;

    if ( as_key == NULL
                || as_val == NULL
                || strlen(as_key) <= 0
                || ai_len <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    //memset( as_val, 0, ai_len );
    iter = mmap_key.find( as_key );
    if ( iter != mmap_key.end() ) {
        snprintf( as_val, ai_len, "%s", (*iter).second.c_str() );
        i_ret = clib_urldecode( as_val, s_buf, sizeof(s_buf) );
        if ( 0 == i_ret ) { 
            snprintf( as_val, ai_len, "%s", s_buf );
        } // if
        return( CLIB_STRMAP_OK );
    } else {
        return( CLIB_STRMAP_ERR_FIND );
    } // if
}
/* }}} */


/* {{{ clib_strmap2::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap2::get_key( const char *as_key,
                          int        &ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    int  i_ret = 0;

    i_ret = this->get_key( as_key, s_buf, sizeof(s_buf) );
    if ( CLIB_STRMAP_OK == i_ret ) {
        ai_val = atoi( s_buf );
    } // if

    return( i_ret );
}
/* }}} */


/* {{{ clib_strmap2::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap2::get_key( const char *as_key,
                          unsigned int        &ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;
    int  i_ret = 0;

    i_ret = this->get_key( as_key, s_buf, sizeof(s_buf) );
    if ( CLIB_STRMAP_OK == i_ret ) {
        ai_val = (unsigned int)atoll( s_buf );
    } // if

    return( i_ret );
}
/* }}} */




/* {{{ clib_strmap2::get_key() */
/**
 * Get key value.
 *
 * @param   as_key      Key name.
 * @param   ai_val      Value.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap2::get_key( const char *as_key,
                          long long    &ai_val )
{
    char s_buf[CLIB_STRMAP_SLEN_SHOR];
    s_buf[0] = 0;
    int  i_ret = 0;

    i_ret = this->get_key( as_key, s_buf, sizeof(s_buf) );
    if ( CLIB_STRMAP_OK == i_ret ) {
        ai_val = atoll( s_buf );
    } // if

    return( i_ret );
}
/* }}} */


/* {{{ clib_strmap2::get_keyname() */
/**
 * Get postion key name.
 *
 * @param   ai_pos      Postion.
 * @param   as_key      Key name.
 * @param   as_len      Key name string length.
 * @return              0: succ,!=0: fail.
 */
int clib_strmap2::get_keyname( const int   ai_pos,
                              char       *as_key,
                              const int   ai_len )
{
    map<string, string>::iterator   iter;
    int i = 0;

    if ( ai_pos < 0
                || as_key == NULL
                || ai_len <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    iter = mmap_key.begin();
    for ( i=0; i<ai_pos; i++ ) {
        iter++;
    } // for

    if ( iter != mmap_key.end() ) {
        snprintf( as_key, ai_len, "%s", (*iter).first.c_str() );
        return( CLIB_STRMAP_OK );
    } else {
        return( CLIB_STRMAP_ERR_FIND );
    } // if
}
/* }}} */


/* {{{ clib_strmap2::count_key() */
/**
 * Get key count number.
 *
 * @return              >=0: count, <0: fail.
 */
int clib_strmap2::count_key()
{
    return( mmap_key.size() );
}
/* }}} */


/* {{{ clib_strmap2::parse() */
/**
 * Parse a key-value string to string map.
 *
 * @param   as_str      build string.
 * @param   ai_len      string length.
 * @param   ac_keysep   key separator, commonly='&'.
 * @param   ac_valsep   key separator, commonly='='.
 * @param   ai_case     whether key case sensitive, 0=no; 1=ya.
 * @return              0: ok, other fail.
 */
int clib_strmap2::parse( const char *as_str,
                        const int   ai_len,
                        const char  ac_keysep,
                        const char  ac_valsep )
{
    char s_delim[CLIB_STRMAP_SLEN_SHOR];
    char s_separ[CLIB_STRMAP_SLEN_SHOR];
    char *s_msg = NULL;
    int  i_pos = 0;
    int  i_end = 0;
    string  str_src;
    string  str_node;
    string  str_key;
    string  str_val;

    if ( as_str == NULL
                || strlen(as_str) <= 0
                || ai_len <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    s_msg = (char *) malloc( ai_len + 8 );
    if ( s_msg == NULL ) {
        return ( CLIB_STRMAP_ERR_SYST );
    } // if             
    //memset( s_msg, 0, sizeof(s_msg) );

    this->reset_key();
    snprintf( s_delim, sizeof(s_delim), "%c", ac_keysep );
    snprintf( s_separ, sizeof(s_separ), "%c", ac_valsep );
    snprintf( s_msg, ai_len+1, "%s", as_str );
    str_src = s_msg;

    i_end = 0;
    while ( !i_end ) {
        i_pos = str_src.find( s_delim );
        if ( i_pos >= 0 ) {
            str_node = str_src.substr( 0, i_pos );
            str_src  = str_src.substr( i_pos+1 );
        } else {
            str_node = str_src;
            str_src  = "";
            i_end    = 1;
        } // if
        i_pos    = str_node.find( s_separ );
        if ( i_pos > 0 ) {
            str_key = str_node.substr( 0, i_pos );
            str_val = str_node.substr( i_pos+1 );
            mmap_key.insert( map<string, string>::value_type(str_key, str_val) );
        } // if
    } // while

    free( s_msg );

    return( CLIB_STRMAP_OK );
}
/* }}} */


/* {{{ clib_strmap2::build() */
/**
 * Build a key-value string by a string map.
 *
 * @param   as_str      build string.
 * @param   ai_len      max length of string.
 * @param   ac_keysep   key separator, commonly='&'.
 * @param   ac_valsep   key/value separator, commonly='='.
 * @return              0: ok, other fail.
 */
int clib_strmap2::build( char      *as_str,
                        const int  ai_len,
                        const char ac_keysep,
                        const char ac_valsep )
{
    string  str_des;
    map<string, string>::iterator   iter;

    if ( as_str == NULL
                || ai_len <= 0 ) {
        return( CLIB_STRMAP_ERR_PARA );
    } // if

    str_des = "";
    for ( iter = mmap_key.begin(); iter != mmap_key.end(); iter++ ) {
        if ( iter != mmap_key.begin() )  str_des += ac_keysep;
        str_des += (*iter).first + ac_valsep + (*iter).second;
    } // for

    snprintf( as_str, ai_len, "%s", str_des.c_str() );
    return( CLIB_STRMAP_OK );
}
/* }}} */




/* {{{ clib_urlencode() */
/**
 * URL Encode.
 *
 * @param   as_src      Source string.
 * @param   as_des      Dest string.
 * @param   ai_len      Max length of desc string.
 * @return              0: ok, other fail.
 */
int clib_urlencode( const char *as_src, char *as_des, const int ai_len )
{
    int  i = 0, j = 0;
    //char s_buf[CLIB_STRMAP_SLEN_TEXT] = { 0 };

    if ( as_src == NULL
                || as_des == NULL
                || ai_len <= 0
                || ai_len > CLIB_STRMAP_SLEN_TEXT ) {
        return( -1 );
    } // if

    i = 0;
    j = 0;
    //memset( s_buf, 0, sizeof(s_buf) );
    //while ( (i < ai_len) && (as_src[i] != '\0') && (j < (int)sizeof(s_buf)-4) ) {
    while ( (i < ai_len) && (as_src[i] != '\0') && (j < ai_len-4) ) {
        switch (as_src[i]) {
        case '\t' :
        case '\n' :
        case '\r' :
        case '$' :
        case '&' :
        case '+' :
        case ',' :
        case '/' :
        case ':' :
        case ';' :
        case '=' :
        case '?' :
        case '@' :
        case ' ' :
        case '%' :
        case '"' :
        case '#' :
            snprintf( as_des+j, ai_len - j - 1, "%%%02X", (unsigned char)as_src[i] );
            break;
        //case ' ' :
        //    s_buf[j] = '+';
        //    j -= 2;
        //    break;
        default:
            as_des[j] = as_src[i];
            j -= 2;
            break;
        } // switch

        i++;
        j += 3;
    } // while

    //snprintf( as_des, ai_len, "%s", s_buf );
    as_des[j] = 0;
    return( 0 );
}
/* }}} */


/* {{{ clib_urldecode() */
/**
 * URL Decode.
 *
 * @param   as_src      Source string.
 * @param   as_des      Dest string.
 * @param   ai_len      Max length of desc string.
 * @return              0: ok, other fail.
 */
int clib_urldecode( const char *as_src, char *as_des, const int ai_len )
{
    int  i = 0, j = 0;
    long l_asc = 0;
    //char s_buf[CLIB_STRMAP_SLEN_TEXT];
    char s_tmp[CLIB_STRMAP_SLEN_SHOR];
    s_tmp[0] = 0;

    if ( as_src == NULL
                || as_des == NULL
                || ai_len <= 0
                || ai_len > CLIB_STRMAP_SLEN_TEXT ) {
        return( -1 );
    } // if

    i = 0;
    j = 0;
    //while ( (i < ai_len) && (as_src[i] != '\0') && (j < (int)sizeof(s_buf)-1) ) {
    while ( (i < ai_len) && (as_src[i] != '\0') && (j < ai_len - 1) ) 
    {
        switch (as_src[i]) 
        {
            case '%' :
                snprintf( s_tmp, 3, "%s", as_src+i+1 );
                l_asc    = strtol( s_tmp, NULL, 16 );
                //s_buf[j] = toascii( l_asc );
                as_des[j] = (char)l_asc;
                i += 2;
                break;
            case '+' :
                as_des[j] = ' ';
                break;
            default:
                as_des[j] = as_src[i];
                break;
        } // switch

        i++;
        j++;
    } // while

    //snprintf( as_des, ai_len, "%s", s_buf );
    as_des[j] = 0;
    return( 0 );
}
/* }}} */




